﻿using System;
using System.Collections.Generic;

public class GameGenie
{
    public bool[] addressMatch = new bool[0x10000];
    private string[] charMapping = new string[] { "a", "p", "z", "l", "g", "i", "t", "y", "e", "o", "x", "u", "k", "s", "v", "n" };
    private List<GameGenieCode> codeList = new List<GameGenieCode>();
    private int[] lut6charMapping = new int[] { 
        20, 0x15, 0x16, 3, 0x10, 0x11, 0x12, 0x17, 4, 5, 6, 11, 12, 13, 14, 0x13, 
        0, 1, 2, 7, 8, 9, 10
     };
    private int[] lut8charMapping = new int[] { 
        0x1c, 0x1d, 30, 3, 0x18, 0x19, 0x1a, 0x1f, 12, 13, 14, 0x13, 20, 0x15, 0x16, 0x1b, 
        8, 9, 10, 15, 0x10, 0x11, 0x12, 4, 5, 6, 11, 0, 1, 2, 7
     };
    public static int TYPE_6CHAR = 0;
    public static int TYPE_8CHAR = 1;

    public virtual void addCode(string code)
    {
        if ((code.Length == 6) || (code.Length == 8))
        {
            GameGenieCode item = new GameGenieCode();
            this.codeList.Add(item);
            item.type = (code.Length == 6) ? TYPE_6CHAR : TYPE_8CHAR;
            item.code = code;
            if (item.type == TYPE_6CHAR)
            {
                item.address = this.get6charAddress(code);
                item.value_Renamed = this.get6charValue(code);
            }
            else
            {
                item.address = this.get8charAddress(code);
                item.value_Renamed = this.get8charValue(code);
                item.compare = this.get8charCompare(code);
            }
            this.addressMatch[item.address] = true;
        }
    }

    public virtual void clearCodes()
    {
        this.codeList.Clear();
        this.updateAddressMatch();
    }

    public virtual long decode6char(string code)
    {
        long num = this.mapChars(code);
        long num2 = 0L;
        for (int i = 0; i < 0x17; i++)
        {
            num2 |= ((num >> (this.lut6charMapping[i] & 0x3f)) & 1L) << i;
        }
        return num2;
    }

    public virtual long decode8char(string code)
    {
        long num = this.mapChars(code);
        long num2 = 0L;
        for (int i = 0; i < 0x1f; i++)
        {
            num2 |= ((num >> (this.lut8charMapping[i] & 0x3f)) & 1L) << i;
        }
        return num2;
    }

    public virtual void editCode(int codeindex, string newCode)
    {
        if ((newCode.Length == 6) || (newCode.Length == 8))
        {
            GameGenieCode code = this.codeList[codeindex];
            code.code = newCode;
            code.type = (newCode.Length == 6) ? TYPE_6CHAR : TYPE_8CHAR;
            if (code.type == TYPE_6CHAR)
            {
                code.address = this.get6charAddress(newCode);
                code.value_Renamed = this.get6charValue(newCode);
            }
            else
            {
                code.address = this.get8charAddress(newCode);
                code.value_Renamed = this.get8charValue(newCode);
                code.compare = this.get8charCompare(newCode);
            }
            this.updateAddressMatch();
        }
    }

    public virtual int get6charAddress(string code)
    {
        return (((int) ((this.decode6char(code) & 0xffff00L) >> 8)) | 0x8000);
    }

    public virtual int get6charValue(string code)
    {
        return (int) (this.decode6char(code) & 0xffL);
    }

    public virtual int get8charAddress(string code)
    {
        return (((int) ((this.decode8char(code) >> 8) & 0x7fffL)) | 0x8000);
    }

    public virtual int get8charCompare(string code)
    {
        return (((int) (this.decode8char(code) >> 0x17)) & 0xff);
    }

    public virtual int get8charValue(string code)
    {
        return (int) (this.decode8char(code) & 0xffL);
    }

    public virtual int getCharNum(string s)
    {
        for (int i = 0; i < this.charMapping.Length; i++)
        {
            if (s.Equals(this.charMapping[i]))
            {
                return i;
            }
        }
        return 0;
    }

    public virtual GameGenieCode getCode(int index)
    {
        return this.codeList[index];
    }

    public virtual int getCodeAddress(int index)
    {
        return this.getCode(index).address;
    }

    public virtual int getCodeCompare(int index)
    {
        return this.getCode(index).compare;
    }

    public virtual int getCodeIndex(int address)
    {
        for (int i = 0; i < this.codeList.Count; i++)
        {
            if (this.getCode(i).address == address)
            {
                return i;
            }
        }
        return 0;
    }

    public virtual string getCodeString(int index)
    {
        return this.getCode(index).code;
    }

    public virtual int getCodeType(int index)
    {
        return this.getCode(index).type;
    }

    public virtual int getCodeValue(int index)
    {
        return this.getCode(index).value_Renamed;
    }

    public virtual long mapChars(string s)
    {
        long num = 0L;
        s = s.ToLower();
        for (int i = 0; i < s.Length; i++)
        {
            num |= this.getCharNum(s.Substring(i, (i + 1) - i)) << (((s.Length - i) - 1) * 4);
        }
        return num;
    }

    public virtual void removeCode(int codeindex)
    {
        this.codeList.RemoveAt(codeindex);
        this.updateAddressMatch();
    }

    public virtual void updateAddressMatch()
    {
        for (int i = 0; i < this.addressMatch.Length; i++)
        {
            this.addressMatch[i] = false;
        }
        for (int j = 0; j < this.codeList.Count; j++)
        {
            this.addressMatch[this.codeList[j].address] = true;
        }
    }

    public virtual int CodeCount
    {
        get
        {
            return this.codeList.Count;
        }
    }
}

